#include <stdafx.h>

#include "DataLoader.h"
#include <iostream>
#include <fstream>
#include <vector>

Eigen::MatrixXd *DataLoader::loadMatrix(const char *path) 
{
    if (path == NULL) {
        return NULL;
    }
    std::ifstream input (path);
    if (!input.is_open()) {
        std::cerr << "Unable to save the matrix. Output file cannot be opened.";
        return NULL;
    }

    Eigen::MatrixXd *m = NULL;
    int nrows = 0, ncols = 0;
    std::vector<std::vector<double> > v;
    // loading special FASTA format
    if (strstr(path, ".fna")) {
        int seqlen = 0;
        int maxcolumns = 0;
        char linebuf[256];
        char lenbuf[8];
        char *pos = 0;
        char c;
        // calculating rows and cols
        while (input.good()) {
            input.getline(linebuf, 256);
            if (pos = strstr(linebuf, "length=")) {
                pos += 7;
                strcpy(lenbuf, pos);
                seqlen = atoi(lenbuf);
            }
            std::vector<double> w(seqlen);
            maxcolumns = std::max(maxcolumns, seqlen);
            //std::vector<double> *w = new std::vector<double>(seqlen);
            for (int i = 0; i < seqlen; ++i) {
                input >> c;
                switch (c) {
                case 'A': w[i] = 1.0; break;
                case 'T': w[i] = 2.0; break;
                case 'G': w[i] = 4.0; break;
                case 'C': w[i] = 5.0; break;
                }
            }
            v.push_back(w);
            input.getline(linebuf, 256);
        }
        // loading data into the matrix
        m = new Eigen::MatrixXd(v.size(), maxcolumns);
        for (int i = 0; i < v.size(); ++i)
            for (int j = 0; j < v[i].size(); ++j)
                (*m)(i,j) = v[i][j];
    }
    // loading default format (ASCII file)
    else {
        input >> nrows;
        input >> ncols;
        m = new Eigen::MatrixXd(nrows, ncols);
        double currVal = 0.0, nextVal = 0.0;
        input >> currVal;
        input >> nextVal;
        for (int i = 0; i < nrows; ++i) {
            for (int j = 0; j < ncols; ++j) {
                (*m)(i,j) = currVal;
                if (!input.good() && j < (ncols-1) && i < (nrows-1)) {
                    std::cerr << "More matrix data expected. Read only " << (i+1) <<
                                 " rows and " << (j+1) << " columns. Expected " << nrows <<
                                 " and " << ncols << std::endl;
                    return NULL;
                }
                currVal = nextVal;
                input >> nextVal;
            }
        }
        input.close();
    }
    return m;
}

int DataLoader::saveMatrix(Eigen::MatrixXd *matrix, const char *path) 
{
    std::ofstream out (path);
    if (!out.is_open()) {
        std::cerr << "Unable to save the matrix. Output file cannot be opened.";
        return 1;
    }
    out << matrix->rows() << " " << matrix->cols() << std::endl <<
           (*matrix) << std::endl;
    out.close();
    return 0;
}
